"""
skills

Various skills and activities of Persons.
"""

import island, port

# Skills map to activities in Activity subclasses.
SKILL_TYPES = (
    ST_HANDCOMBAT,  # Various slashing, bludgeoning, piercing weapons.
    ST_AIMCOMBAT,   # Forts or Ships - projectile weapons.
    ST_WEAPON,      # Specific weapon
    ST_NAVIGATE,
    ST_VISION,
    ST_WIND,
    ST_SWIM,
    ST_LUCK,
    ST_BUILD,
    ST_STRENGTH,
    ST_SPEED,
    ST_LOYAL,
    ST_NEGOTIATION, # Includes bribing officials, haggling with traders
    ST_MEDICINE     # Heals self and others quickly
    ) = range(14)

# Things for persons to do
#Proegssilb: Don't limit options here; I've purposely set a ship on fire, sniff a flower,
#            attempted to pick the same flower (failed), seen someone else try to climb a
#            building, grapple up the same building, etc. At the minimum, there should be
#            a special action known to the user as "other".
ACTIVITY_TYPES = (
    # Anchored activities
    AT_EMBARK,
    AT_DISEMBARK,

    # Sailing activities
    AT_REST,
    AT_NAVIGATE,
    AT_STEER,
    AT_LOOKOUT,
    AT_BUILD,
    AT_DAMAGECONTROL,
    AT_HEAL,
    AT_SWIM,
    AT_FISH,
    AT_ROW,
    AT_SWABDECK,
    AT_REEF,
    AT_UNREEF,
    AT_COOK,
    AT_ANCHOR,
    AT_UNANCHOR,
    
    # Combat activities
    AT_FLAGUP,
    AT_FLAGDOWN,
    AT_AIMATTACK,
    AT_HANDATTACK,
    AT_GRAPPLE,
    AT_BOARD,
    
    # Island activities
    AT_FOLLOWMAP,
    AT_DIG,
    AT_RETURN,
    
    # Port activities
    AT_LOAD,
    AT_UNLOAD,
    AT_REPAIR,
    #...
    
    ) = range(30)



class ActivityImpossible(Exception):
    def __init__(self, activity):
        Exception.__init__(self)
        self.activity = activity



class Activity:
    """ Any kind of activity. """
    reqpersons = 1

    def perform(self, person):
        """
        Continue executing the activity.  Effectiveness should be
        determined by the skill level of the person.
        """
        raise NotImplementedError





class BoatActivity(Activity):
    """ Some activity involving the ship. """    
    def __init__(self, boat):
        self.boat = boat
        
    def perform(self, person):
        # Make sure they're on the boat.
        if person.boat is not self.boat:
            raise ActivityImpossible(self)
        
        self.checkReqPersons(person)
    
    def checkReqPersons(self, person):
        """ Check how many others are doing this activity. """
        if self.reqpersons == 1:
            return
        
        bmode = self.boat.mode
        others = [ pirate
                   for pirate in self.boat.crew
                   if pirate.assignments[bmode].atype == self.atype ]
        if self.reqpersons > len(others):
            raise ActivityImpossible(self)

class Anchor(BoatActivity):
    """ Drop the anchor. """
    atype = AT_ANCHOR
    reqpersons = 2

    def perform(self, person):
        BoatActivity.perform(self, person)
        person.boat.anchored = True
        
class HoistAnchor(BoatActivity):
    """ Hoist the anchor. """
    atype = AT_UNANCHOR
    reqpersons = 2
    
    def perform(self, person):
        BoatActivity.perform(self, person)
        person.boat.anchored = False





class BoatLandActivity(Activity):
    """ An interaction between a boat and an island or port. """
    boat = None
    island = None
    port = None

    def __init__(self, boat, land):
        # <land> can be an island or port.
        self.boat = boat
        if isinstance(land, port.Port):
            self.port = land
        elif isinstance(land, island.Island):
            self.island = land
        else:
            raise ValueError, land

    def perform(self, person):
        # Make sure they're on the boat.
        if person.boat is not self.boat:
            raise ActivityImpossible(self)
        
        self.checkReqPersons(person)

    def checkReqPersons(self, person):
        """ Check how many others are doing this activity. """
        if self.reqpersons == 1:
            return
        
        bmode = self.boat.mode
        others = [ pirate
                   for pirate in self.boat.crew
                   if pirate.assignments[bmode].atype == self.atype ]
        if self.reqpersons > len(others):
            raise ActivityImpossible(self)

        
class Embark(BoatLandActivity):
    """ Get a person onto the ship. """
    atype = AT_EMBARK
    
    def perform(self, person):
        if person.boat is not None:
            raise ActivityImpossible(self)

        if not self.boat.anchored:
            raise ActivityImpossible(self)

        if not (self.boat.port == self.port and
                self.boat.island == self.island):
            raise ActivityImpossible(self)

        if not (self.island is person.island or
                self.port is person.port):
            raise ActivityImpossible(self)

        person.boat = self.boat
        person.island = None
        person.port = None
    
class Disembark(BoatLandActivity):
    """ Get a person off the ship. """
    atype = AT_DISEMBARK
    
    def perform(self, person):
        if person.boat is not self.boat:
            raise ActivityImpossible(self)

        if not self.boat.anchored:
            raise ActivityImpossible(self)

        # One of these is none.  So should the boat's be.
        if not (self.boat.port == self.port and
                self.boat.island == self.island):
            raise ActivityImpossible(self)

        if (self.island and person.island is not None or
            self.port and person.port is not None):
            raise ActivityImpossible(self)
        
        person.island = self.island
        person.port = self.port
        person.boat = None


class Rest(Activity):
    """ Sleep, regaining health. """
    
    def perform(self, person):
        if person.port is not None:
            #TODO: Costs money to sleep here
            pass
        
        person.health += 2
        if ST_MEDICINE in person.skills:
            qty = person.skills[ST_MEDICINE]
            person.health += qty




class PersonSubjectActivity(Activity):
    """ An interaction with another person. """
    def __init__(self, person, atype=None):
        Activity.__init__(self, atype)
        self.other = person


class Heal(PersonSubjectActivity):
    """ Heal the other person. """
    atype = AT_HEAL
    
    def perform(self, person):
        #TODO: check for being near the other person.
        self.other.health += dice.dice1d4.roll()
        if ST_MEDICINE in person.skills:
            qty = person.skills[ST_MEDICINE]
            self.other.health += dice.dice1d4.roll()
            self.other.health += qty









class Duty(Activity):
    """
    The default role activity for a Role/Mode combination.
    """
    
    def __init__(self, role, mode):
        self.role = role
        self.mode = mode
    
    def perform(self, person):
        """
        Continue executing the duty schedule.   Effectiveness should be
        determined by the skill level of the person.
        """
        raise NotImplementedError


class PirateDuty(Duty):
    def perform(self, person):
        pass

